#include "OpenGlClass.h"
#pragma comment( lib, "opengl32.lib" )
#pragma comment( lib, "glu32.lib" )

#include <gl\gl.h>          // Header File For The OpenGL32 Library
#include <gl\glu.h>         // Header File For The GLu32 Library

/*******************************************************************************
  Window Class
*******************************************************************************/
OpenGLWindow::OpenGLWindow() {
  SetWndTitle( "Basic OpenGL Window" );
}

OpenGLWindow::~OpenGLWindow() {
}

bool OpenGLWindow::Create() {
  Window::SetClassStyle( GetClassStyle() | CS_OWNDC );

  Window::RegisterIfNoProc( WM_ACTIVATE, OpenGLWindow::DefGLActivate );
  Window::RegisterIfNoProc( WM_PAINT, OpenGLWindow::DefGLPaint );

  if( !Window::Create() ) {
    return false;
  }
  GeneratePFD();

  // Create the OpenGL context
  if( !( GetDC() && GetPixelFormat() && SetPixelFormat() &&
         CreateContext() && MakeCurrent() ) ) {
    Window::Destroy();
    return false;
  }

  return true;
}

void OpenGLWindow::Destroy() {
  if( Window::IsActive() ) {
    if( !wglMakeCurrent( NULL, NULL ) ) {
      MessageBox( NULL, "Release Of DC And RC Failed.", "ERROR",
                  MB_OK | MB_ICONEXCLAMATION );
    }
    if( hRC && !wglDeleteContext( hRC ) ) {
      MessageBox( NULL, "Release Rendering Context Failed.", "ERROR",
                  MB_OK | MB_ICONEXCLAMATION );
    }
	  if( hDC && !ReleaseDC( GetHwnd(), hDC ) ) {
	    MessageBox( NULL, "Release Device Context Failed.", "ERROR",
	                MB_OK | MB_ICONEXCLAMATION );
		}
	  hRC = NULL;
	  hDC = NULL;
	}
  Window::Destroy();
}

void OpenGLWindow::SwapBuffers() {
  ::SwapBuffers(hDC);
}

bool OpenGLWindow::MakeCurrent() {
  if( !wglMakeCurrent( hDC, hRC ) ) {
    MessageBox( NULL, "Can't Active The GL Rendering Context.", "ERROR",
                MB_OK | MB_ICONEXCLAMATION );
    return false;
  }
  return true;
}

bool OpenGLWindow::GetDC() {
  if( !( hDC = ::GetDC( GetHwnd() ) ) ) {
    MessageBox( NULL, "Failed To Create A GL Device Context.", "ERROR",
                MB_OK | MB_ICONEXCLAMATION );
    return false;
  }
  return true;
}

void OpenGLWindow::GeneratePFD() {
  memset( &pfd, 0, sizeof(pfd) );
  pfd.nSize = sizeof( PIXELFORMATDESCRIPTOR );
  pfd.nVersion = 1;
  pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
  pfd.cColorBits = 32;
  pfd.cDepthBits = 16;
}

bool OpenGLWindow::GetPixelFormat() {
  if( !( pixelFormat = ::ChoosePixelFormat( hDC, &pfd ) ) ) {
    MessageBox( NULL, "Can't Find Suitable Pixel Format.", "ERROR",
                MB_OK | MB_ICONEXCLAMATION );
    return false;
  }
  return true;
}

bool OpenGLWindow::SetPixelFormat() {
  if( !::SetPixelFormat( hDC, pixelFormat, &pfd ) ) {
    MessageBox( NULL, "Can't Set The Pixel Format.", "ERROR",
                MB_OK | MB_ICONEXCLAMATION );
    return false;
  }
  return true;
}

bool OpenGLWindow::CreateContext() {
  if( !( hRC = wglCreateContext( hDC ) ) ) {
    MessageBox( NULL, "Can't Create A GL Rendering Context.", "ERROR",
                MB_OK | MB_ICONEXCLAMATION );
    return false;
  }
  return true;
}

long OpenGLWindow::DefGLActivate( Window& win, long wparam, long lparam ) {
  OpenGLWindow& glp = (OpenGLWindow&)win;
  switch( LOWORD(wparam) ) {
    case WA_ACTIVE:
    case WA_CLICKACTIVE:
      glp.MakeCurrent();
      break;
    case WA_INACTIVE:
      wglMakeCurrent( NULL, NULL );
    	break;
  }
  Window::DefWndActivate( win, wparam, lparam );
  return 0;
}

long OpenGLWindow::DefGLPaint( Window& win, long wparam, long lparam ) {
  OpenGLWindow& glp = (OpenGLWindow&)win;
  glp.DefGLPaintBegin();
  glp.DefGLPaintEnd();
  return 0;
}

long OpenGLWindow::DefGLPaintBegin() {
  MakeCurrent();
  return 0;
}

long OpenGLWindow::DefGLPaintEnd() {
  SwapBuffers();
  return 0;
}
